package captcha

import (
	"fmt"
	"github.com/gogf/gf/database/gredis"
	"github.com/gogf/gf/frame/g"
	"github.com/gogf/gf/util/gconv"
	"strings"
	"time"
)

// RedisStore 使用redis实现了验证码的存储功能, 不再使用自带的内存存储
var RedisStore = redisStore{
	redis:      g.Redis(),                            // 使用gf的Redis组件
	expiration: gconv.Int(5 * time.Minute.Seconds()), // 默认过期时间: 5min
}

type redisStore struct {
	redis      *gredis.Redis // redis实例对象
	expiration int           // 过期时间, 单位为秒
}

// Set 设置验证码id及验证码内容
func (r *redisStore) Set(id string, value string) {
	// 获取在redis中的键
	key := r.getKey(id)
	// 直接在redis中进行设置
	_, err := r.redis.Do("SETEX", key, r.expiration, value)
	if err != nil {
		g.Log().Errorf("redis错误: %v", err)
	}
}

// Get 通过验证码id获取验证码, 如果第二个参数为ture, 则在获取后对验证码进行清除
func (r *redisStore) Get(id string, clear bool) string {
	// 获取在redis中的键
	key := r.getKey(id)
	// 发送GET命令获取值
	value, err := r.redis.DoVar("GET", key)
	if err != nil {
		g.Log().Errorf("redis错误: %v", err)
		return ""
	}
	// 如果指定了clear选项, 就执行DEL进行清除
	if clear {
		_, err := r.redis.Do("DEL", key)
		if err != nil {
			panic(err)
		}
	}
	return value.String()
}

// Verify 校验answer是否与id对应的验证码相同, 如果第二个参数为ture, 那么就在验证后进行删除
func (r *redisStore) Verify(id, answer string, clear bool) bool {
	// 获取redis中存储的实际值
	target := r.Get(id, clear)
	if target == "" { // 返回值为空, 代表获取值失败
		return false
	}
	// 比较的时候忽略大小写
	return strings.ToLower(target) == strings.ToLower(answer)
}

// getKey 通过验证码的id获取存储在redis中的键
func (r *redisStore) getKey(id string) string {
	return fmt.Sprintf("captcha:%s", id)
}
